import { Component, VueConstructor } from 'vue'

export interface Config {
  routes: RouteConfig[]
}

export interface RouteConfig {
  path: string;
  name: string;
  component: Component;
}

export interface RouteData {
  current: string;
}

let _Vue!: VueConstructor;

export default class VueRouter {
  constructor(options: Config) {
    this.options = options;
    this.data = _Vue.observable({ current: '/' })
    this.init();
  }

  static installed = false;
  data!: RouteData;
  options: Config | null = null;
  routeMap: Record<string, Component> = {};

  static install(Vue: VueConstructor) {
    if (this.installed && Vue === _Vue) return;
    _Vue = Vue;
    this.installed = true;
    _Vue.mixin({
      beforeCreate(){
        // @ts-ignore
        if(this.$options.router){
          // @ts-ignore
          _Vue.prototype.$router = this.$options.router
        }
      }
    })
  }

  init() {
    this.createRouteMap();
    this.initComponents(_Vue);
    this.initEvent();
  }

  initEvent() {
    window.addEventListener('hashchange', () => {
      console.log(window.location.hash);
      if (this.data) {
        this.data.current = window.location.hash.slice(1);
      }
    })
  }

  createRouteMap() {
    this.options?.routes.forEach(route => {
      this.routeMap[route.path] = route.component;
    })
    console.log(this.routeMap)
  }

  initComponents(Vue: VueConstructor) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        return h('a', {
          attrs: {
            href: '#' + this.to
          },
        }, [this.$slots.default])
      },
    })
    const _this = this;
    Vue.component('router-view', {
      render(h) {
        const comp = _this.routeMap[_this.data.current]
        return h(comp)
      }
    })
  }
}
